package com.SpringAOP.test_1_31_springaop.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
//@Component
public class AspectDemo {
    @Pointcut("execution(* com.SpringAOP.test_1_31_springaop.controller.*.*(..))") // 定义一个切点
    public void pt(){// 切点的名字叫 pt 这个是自定义的
        // 那么这个切点是否可以让其他类使用呢?
        // 如果其他类需要使用, 需要把切点声明为 public
        // 使用时, 类的全限定名称(包+类名)+切点名称

        // 当多个类 都用这个切点的时候
        // 有多个切面时, 切面的执行顺序时按照名称的顺序来执行的
        // before 执行越早的 after 执行越晚

        // 也就是说 先执行Before 时 优先级更高 同时后执行 After
    }
    @Before("pt()")
    public void doBefore(){
        log.info("AspectDemo, before...");
    }

    @After("pt()")
    public void doAfter(){
        log.info("AspectDemo, After...");
    }

    @AfterReturning("pt()")
    public void doAfterReturning(){
        log.info("AspectDemo, AfterReturning...");
    }

    @AfterThrowing("execution(* com.SpringAOP.test_1_31_springaop.controller.*.*(..))")
    public void doAfterThrowing(){
        log.info("AspectDemo, AfterThrowing...");
    }

    @Around("execution(* com.SpringAOP.test_1_31_springaop.controller.*.*(..))")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("AspectDemo, Around前...");
        Object result = joinPoint.proceed();
        log.info("AspectDemo, Around后...");
        return  result;   // Around 这个注解必须要有返回结果, 这是固定的一个写法
    }

    //可以看到执行的先后顺序
    // 是先执行: Around前
    // 然后执行: Before
    // 再然后执行: AfterReturning
    // 再执行: After
    // 最后执行: Around后

    // 而AfterThrowing是异常之后执行的
    // 有了异常之后 执行的顺序就变为了
    // 是先执行: Around前
    // 然后执行: Before
    // 再然后执行: AfterThrowing  // 不执行 AfterReturning 了, 也不执行 Around后
    // 最后执行: After
}
